package data

import (
	"commerce/cache"
	"commerce/common"
	"commerce/vo"
	"encoding/json"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"sort"
	"strconv"
	"strings"
)

const cART_PREFIX = "mall:cart:"
const bUY_PREFIX = "mall:buy:"

// 直接购买商品（也通过类似购物车机制暂时保存起来）

func BuyToCart(userId, skuId, num int) (item *vo.CartItem, err error) {

	hashKey := bUY_PREFIX + strconv.Itoa(userId)
	key := strconv.Itoa(skuId)

	goods, err := cache.HGet(hashKey, key)
	if err != nil && err != redis.ErrNil {
		return nil, err
	}
	if len(goods) == 0 {
		item = getNewCartItem(skuId, num)
		if item == nil {
			return nil, fmt.Errorf("BuyToCart无效商品sku id：%d", skuId)
		}
		item.Sort = determineSort(hashKey)

		itemBytes, _ := json.Marshal(item)
		cache.HSet(hashKey, key, string(itemBytes))
	} else {
		json.Unmarshal([]byte(goods), &item)
		item.Count += num

		itemBytes, _ := json.Marshal(item)
		cache.HSet(hashKey, key, string(itemBytes))
	}
	return item, nil
}

func AddToCart(userId, skuId, num int) (item *vo.CartItem, err error) {

	hashKey := cART_PREFIX + strconv.Itoa(userId)
	key := strconv.Itoa(skuId)

	goods, err := cache.HGet(hashKey, key)
	if err != nil && err != redis.ErrNil {
		return nil, err
	}
	if len(goods) == 0 {
		item = getNewCartItem(skuId, num)
		if item == nil {
			return nil, fmt.Errorf("无效商品sku id：%d", skuId)
		}
		item.Sort = determineSort(hashKey)

		itemBytes, _ := json.Marshal(item)
		cache.HSet(hashKey, key, string(itemBytes))
	} else {
		json.Unmarshal([]byte(goods), &item)
		item.Count += num

		itemBytes, _ := json.Marshal(item)
		cache.HSet(hashKey, key, string(itemBytes))
	}
	return item, nil
}

func ClearBuyCart(userId int) error {

	_, err := cache.Delete(bUY_PREFIX + strconv.Itoa(userId))
	return err
}

func ClearCart(userId int) error {

	_, err := cache.Delete(cART_PREFIX + strconv.Itoa(userId))
	return err
}

func DeleteCartItem(userId, goodsId int) error {

	return cache.HDel(cART_PREFIX+strconv.Itoa(userId), strconv.Itoa(goodsId))
}

func UpdateCartItemCount(userId, goodsId, num int) error {

	item, err := GetCartItemByGoodsId(userId, goodsId)
	if err != nil {
		return err
	}
	item.Count = num

	bytes, _ := json.Marshal(item)

	return cache.HSet(cART_PREFIX+strconv.Itoa(userId), strconv.Itoa(goodsId), string(bytes))
}

func GetCartItemByGoodsId(userId, goodsId int) (item *vo.CartItem, err error) {

	itemS, err := cache.HGet(cART_PREFIX+strconv.Itoa(userId), strconv.Itoa(goodsId))
	if err != nil {
		return nil, err
	}
	if len(itemS) == 0 {
		return nil, fmt.Errorf("无效数据")
	}
	json.Unmarshal([]byte(itemS), &item)
	return item, nil
}

func GetCart(userId int) (*vo.Cart, error) {

	if userId > 0 {
		all, err := cache.HGetAll(cART_PREFIX + strconv.Itoa(userId))
		if err != nil {
			return nil, err
		}
		var cart vo.Cart
		var items = make([]vo.CartItem, 0)
		var total = vo.CartTotal{CheckedGoodsCount: 0, CheckedGoodsAmount: 0}
		for _, v := range all {
			var item vo.CartItem
			err := json.Unmarshal([]byte(v), &item)
			if err != nil {
				common.Error.Println(err)
				continue
			}
			if item.Checked {
				total.CheckedGoodsCount += item.Count
				total.CheckedGoodsAmount += item.GetAmount()
			}
			item.SpecNameAttrs = strings.Join(item.SkuAttrs, ",")
			item.SkuAttrs = nil

			sku, err := GetSkuById(item.SkuId)
			if err != nil {
				common.Error.Println(err)
			} else {
				item.SkuName = sku.Name
				// 以最新价格为准
				item.Price = sku.RealPrice
				item.SkuImg = sku.MainImg
			}
			items = append(items, item)
		}
		sort.Slice(items, func(i, j int) bool {
			return items[i].Sort-items[j].Sort <= 0
		})
		cart.CartItems = items
		totalPrice := total.CheckedGoodsAmount
		totalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", totalPrice), 64)
		total.CheckedGoodsAmount = totalPrice

		cart.CartTotal = total

		return &cart, nil
	}
	return nil, fmt.Errorf("请先登录！！")
}

func GetCartGoodsCount(userId int) (int, error) {

	if userId > 0 {
		all, err := cache.HGetAll(cART_PREFIX + strconv.Itoa(userId))
		if err != nil {
			return 0, err
		}
		var count = 0
		for _, v := range all {
			var item vo.CartItem
			err := json.Unmarshal([]byte(v), &item)
			if err != nil {
				common.Error.Println("GetCartGoodsCount err:", err)
				continue
			}
			count += item.Count
		}
		return count, nil
	}
	return 0, fmt.Errorf("请先登录！！")
}

func CheckItem(userId, skuId int, checked bool) error {

	item, err := GetCartItemByGoodsId(userId, skuId)
	if err != nil {
		return err
	}
	item.Checked = checked

	hashKey := cART_PREFIX + strconv.Itoa(userId)
	key := strconv.Itoa(skuId)

	itemBytes, _ := json.Marshal(item)
	cache.HSet(hashKey, key, string(itemBytes))

	return nil
}

func ListBuyCheckedItems(userId int) (*vo.Cart, error) {

	return listCheckedItems(bUY_PREFIX, userId)
}

func ListCheckedItems(userId int) (*vo.Cart, error) {

	return listCheckedItems(cART_PREFIX, userId)
}

func listCheckedItems(key string, userId int) (*vo.Cart, error) {

	all, err := cache.HGetAll(key + strconv.Itoa(userId))
	if err != nil {
		return nil, err
	}
	var cart vo.Cart
	var items = make([]vo.CartItem, 0)
	var total = vo.CartTotal{CheckedGoodsCount: 0, CheckedGoodsAmount: 0}
	for _, v := range all {
		var item vo.CartItem
		err := json.Unmarshal([]byte(v), &item)
		if err != nil {
			common.Error.Println(err)
			continue
		}
		// 只结算 用户勾选项
		if item.Checked {
			total.CheckedGoodsCount += item.Count
			total.CheckedGoodsAmount += item.GetAmount()

			item.SpecNameAttrs = strings.Join(item.SkuAttrs, ",")
			item.SkuAttrs = nil

			sku, err := GetSkuById(item.SkuId)
			if err != nil {
				common.Error.Println(err)
				continue
			} else {
				item.SkuName = sku.Name
				// 以最新价格为准
				item.Price = sku.RealPrice
				item.SkuImg = sku.MainImg
			}
			items = append(items, item)
		}
	}
	sort.Slice(items, func(i, j int) bool {
		return items[i].Sort-items[j].Sort <= 0
	})
	cart.CartItems = items
	totalPrice := total.CheckedGoodsAmount
	totalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", totalPrice), 64)
	total.CheckedGoodsAmount = totalPrice

	cart.CartTotal = total

	return &cart, nil
}

func getNewCartItem(skuId, num int) *vo.CartItem {

	var item = vo.CartItem{SkuId: skuId, Count: num}

	sku, err := GetSkuById(skuId)
	if err != nil {
		return nil
	}
	item.SkuName = sku.Name
	item.Checked = true
	item.Price = sku.RealPrice
	item.SkuImg = sku.MainImg

	skuAttrValues, err := ListSkuAttrValueBySkuId(skuId, false)
	if err == nil && skuAttrValues != nil {
		var buffer strings.Builder
		var skuAttrs []string
		for _, s := range skuAttrValues {
			buffer.Reset()
			buffer.WriteString(s.AttrName)
			buffer.WriteByte(':')
			buffer.WriteString(s.AttrValue)
			skuAttrs = append(skuAttrs, buffer.String())
		}
		item.SkuAttrs = skuAttrs
	}
	return &item
}

func determineSort(key string) int {

	all, err := cache.HGetAll(key)
	if err != nil || all == nil {
		return 0
	}
	return len(all)
}
